﻿
#pragma once

#include "base/core/singleton.h"
#include "Common/DuplicateDefine.h"
#include "Active/ActiveCharacterMgr.h"
#include "DupTeamState.h"
#include "base/core/singleton.h"
#include "base/core/object_pool.h"
#include "Common/CharacterDefine.h"
#include "Common/Timer/TimerAxis.h"
#include "DupQueue.h"
#include "Common/UnionDefine.h"

// teamid - DupTeamState
typedef unordered_map<uint32_t, DupTeamState*> DupTeamStateMap;

class CenterDuplicateMgr : public ICharacterObserver,public ITimerHandler,  public ManualSingleton<CenterDuplicateMgr>
{
	friend class ManualSingleton<CenterDuplicateMgr>;
	enum
	{
		ETimer_ID_Check_Queue = 1, //检查排队
	};
	typedef unordered_map<int32_t, DupQueue*> DupQueueMap; //副本排队map
public:
	CenterDuplicateMgr();
	~CenterDuplicateMgr();
	bool Init();
	void UnInit();

	//////////////////////////////////////////////////////////////////////////
	DupTeamState *MakeTeamStateObj();
	void FreeTeamStateObj(DupTeamState *pObj);
	void RecycleTeamState(DupTeamState *pTeamState);

	int32_t NewQueueId() { return ++m_queueUID; };
	DupQueue *CreateQueue();
	DupQueue *MakeQueueObj();
	void FreeQueueObj(DupQueue *pObj);
	void RecycleQueue(DupQueue *pTeamState);
	void LogicCrash(uint32_t logicId);
	///////////////////////////////// ICharacterObserver /////////////////////////////////////////
	//角色登陆
	virtual void onCharacterLogin(ActiveCharacter *pOnlineCharacter);
	//角色登出
	virtual void onCharacterLogout(ActiveCharacter *pOnlineCharacter);
	//角色更新
	virtual void onCharacterUpdate(ActiveCharacter *pOnlineCharacter);
	//删除角色
	virtual void onCharacterDel(OfflineCharacterData *pOffLineCharacter);
	virtual void onCharacterSwitchScene(ActiveCharacter *pOffLineCharacter){ _UNUSE(pOffLineCharacter); }
	//断开连接
	virtual void onCharacterDisconnect(ActiveCharacter *pOnlineCharacter){ _UNUSE(pOnlineCharacter); };
	//////////////////////////////// ITimerHandler  //////////////////////////////////////////
	virtual void OnTimer(uint32_t nTimerID);
public:
	//创建副本
	dupInfo *createDuplicate(dupInfo &info);
	//获取副本
	dupInfo *getDuplicate(uint32_t sceneId);
	//能否进入竞技场副本
	int32_t canEnterArenaDup(CharIDType charId);
	//进入竞技场 
	int32_t enterArenaDup(CharIDType charId, const CharacterMirrorData &mirrorData);
	//进入挑战阵营首领副本
	int32_t enterCampDup(CharIDType charId, const CharacterMirrorData &mirrorData);
	//进入切磋副本
	int32_t enterCompete(CharIDType charId, CharIDType dstId);
	//能否进入工会驻地
	int32_t canEnterUnionHomeDup(CharIDType charId, uint32_t sceneId);
	//能否进入工会地宫
	int32_t canEnterUnionDungeon(CharIDType charId);
	//进入工会相关副本景
	int32_t enterUnionSceneDup(SUnionSceneParam &param);
	//进入工会地宫
	int32_t enterUnionDungeon(CharIDType charId);
	//创建工会驻地副本
	int32_t createUnionHomeDup(uint32_t unionId,int32_t lev);
	//进入新手引导副本
	dupInfo * enterGuideDup(CharIDType charId, uint32_t dupId);
	//能否进副本
	int32_t canEnterDup(CharIDType charId, uint32_t dupId, int8_t keyType, uint64_t keyValue,int8_t unionSceneType = EUnionSceneType_None);
	//进入副本
	int32_t enterDupReq(LogicToCenter_EnterDupReq &enterProto, uint32_t &dupSceneId, bool notifyLogic = true);
	//进入副本扩展处理
	int32_t enterDupExReq(dupInfo *pdupInfo);
	//玩家是否在副本中
	bool isCharInDup(CharIDType charId);
	//通知玩家进副本失败
	void notifyEnterFailed(CharIDType charId, uint32_t duplId, int32_t retcode);
	//创建新手副本



	//等待玩家进入副本
	bool waitEnter(CharIDType charId, uint32_t sceneId);
	//玩家进入副本
	bool enterDup(CharIDType charId, uint32_t sceneId, int32_t result);
	//玩家离开副本
	bool leaveDup(CharIDType charId, uint32_t sceneId);
	//副本开始
	bool dupBegin(uint32_t sceneId);
	//副本结束 
	bool dupEnd(uint32_t sceneId,int32_t res);
	//副本销毁
	bool dupDestory(uint32_t sceneId);
	//工会解散
	bool unionDismiss(uint32_t sceneId);
	//工会云端试炼活动结束
	bool unionActEnd(uint32_t sceneId);


	//登录是否能进入
	bool loginCanEnter(uint32_t sceneId,CharIDType charId);
	//生物切场景是否能进入
	bool transCanEnter(uint32_t sceneId, uint64_t creature_cid, int32_t creature_kind);
	//获取副本场景所在的逻辑服ID
	uint32_t dupSceneLogic(uint32_t sceneId);

	//获取排队人数上限
	bool getQueueMaxNum(int32_t &maxNum,int32_t &injectInitNum, int32_t &surviveInitNum);
	//是否在排队
	bool inQueue(CharIDType charId);
	//能否加入排队
	int32_t canJoinQueue(CharIDType charId);
	//加入排队
	DupQueue * joinQueue(CharIDType charId);
	//能否取消排队
	int32_t canCancelQueue(CharIDType charId);
	//取消排队
	bool cancelQueue(CharIDType charId);
	//通知进入排队
	void notifyJoinQueue(SET_UINT64 &setChar);
	//加入排队
	DupQueue * onJoinQueue(SET_UINT64 &setChar, uint32_t teamId = 0, bool notify = true);



	//获取等待玩家进入副本返回
	dupWaitRet *getDupWaitRet(CharIDType charId);
	//增加等待玩家进入副本返回
	void addDupWaitRet(CharIDType charId, uint32_t sceneId);
	//删除等待玩家进入副本返回
	void delDupWaitRet(CharIDType charId);

	//获取副本玩家数据
	uint32_t getDupChar(CharIDType charId);
	//增加副本玩家数据
	void addDupChar(CharIDType charId, uint32_t sceneId);
	//删除副本玩家数据
	void delDupChar(CharIDType charId);


	//获取等待创建工会云端试炼副本
	uint32_t getWaitCreateUnion(uint32_t unionId);
	//添加等待创建工会云端试炼副本
	void addWaitCreateUnion(uint32_t unionId,uint32_t sceneId);
	//删除等待创建工会云端试炼副本
	void delWaitCreateUnion(uint32_t unionId);

	//获取副本队伍状态
	DupTeamState *getDupTeamState(uint32_t teamId);
	//是否能邀请进副本
	int32_t canInviteEnter(CharIDType charId, uint32_t dupId, Team *&pOutTeam);
	//邀请进副本
	DupTeamState * inviteEnter(CharIDType charId, uint32_t dupId);
	//能否回复邀请
	int32_t canReplyInvite(CharIDType charId, uint32_t dupId);
	//回复邀请
	DupTeamState *replyInvite(CharIDType charId, int8_t reply);


	//获取玩家进入之前所在的区域
	uint32_t getCharEnterArea(CharIDType charId);
	//增加玩家进入之前所在的区域
	void addCharEnterArea(CharIDType charId, uint32_t areaId);
	//删除玩家进入之前所在的区域
	void delCharEnterArea(CharIDType charId);

	//获取等待副本数据
	dupInfo *getWaitDuplicate(uint32_t sceneId);
	//获取等待创建副本数据
	uint32_t getWaitCreate(CharIDType charId);
	//增加玩家等待创建副本数据
	void addWaitCreate(CharIDType charId, uint32_t sceneId);
	//删除玩家等待创建副本数据
	void delWaitCreate(CharIDType charId);


	//删除一个等待副本数据
	void delWaitDuplicate(uint32_t sceneId,int32_t res = RET_SUCCESS);
	//创建一个等待副本数据
	dupInfo *createWaitDup(uint32_t dupId, int8_t dupType, uint32_t mapId, LogicToCenter_EnterDupReq &enterProto,bool notifyLogic);
	//通知玩家进副本
	bool notifyCreateSuccess(uint32_t sceneId);
	/*	通知进入副本   
		sceneId:副本场景ID
		charId:进入副本的玩家ID ( 现在除了工会驻地场景和 云端试炼 需要传值，其他都不需要 )
	*/
	bool notifyEnterDup(uint32_t sceneId, CharIDType charId = 0);
public:
	//获取新手引导步骤配置
	const GuideStepCfgInfo *GetGuideStepCfg(uint32_t race, uint32_t step);
	//最大步骤
	uint32_t GetGuideMaxStep();
private:
	//加载新手引导步骤配置
	bool LoadGuideStepCfg();
private:
	//通知玩家进入副本
	bool notifyCharEnterDup(CharIDType charId, dupInfo *pdupInfo);
private:
	//分配玩家出生点
	bool allocCharBorn(SET_UINT64 &setChar,uint32_t mapId,int32_t injectNum,int32_t surviveNum,MAP_UINT64_UINT32 &mapCharBorn);
	//获取队列
	DupQueue *getQueue(int32_t queueId);
	//获取玩家所在的排队
	DupQueue *getCharQueue(CharIDType charId);
	//队伍是否在排队
	bool teamQueue(uint32_t teamId);
	//能否容纳
	DupQueue *canAddQueue(SET_UINT64 &setChar,uint32_t teamId = 0);
	//能否匹配
	DupQueue *canMatchQueue(SET_UINT64 &setChar, uint32_t teamId = 0);
	//能否替换
	DupQueue *canReplace(uint32_t teamId, SET_UINT64 &setChar, uint32_t &replaceTeamId, SET_UINT64 &setMember);
	//检查排队，是否能匹配进入副本
	void checkQueue();
	
private:
	//所有逻辑节点的副本数据
	DupDataMap m_mapDupData;
	//玩家在副本中数据 charid - sceneid
	MAP_UINT64_UINT32 m_mapDupChar;
	//等待玩家进入副本数据
	DupWaitRetMap m_mapWaitRet;


	//等待逻辑服创建副本返回的副本数据
	DupDataMap m_mapWaitDupData;
	//玩家等创建副本的数据 charid - sceneid 
	MAP_UINT64_UINT32 m_mapWaitCreate;
	//记录玩家进入场景之前所在的区域
	MAP_UINT64_UINT32 m_charEnterArea;
	//
	ObjectPool<DupTeamState> *m_pDupTeamStatePool;
	//副本队伍状态
	DupTeamStateMap m_teamState;

	//
	ObjectPool<DupQueue> *m_pDupQueuePool;
	//队列UID
	int32_t m_queueUID;
	//副本排队
	DupQueueMap m_mapQueue;

	//等待创建工会相关的副本 unionId - sceneId
	MAP_UINT32_UINT32 m_mapWaitCreateUnion;

	//新手引导副本种族步骤出生点配置信息
	VecGuideRaceCfg m_vecGuideCfg;
};


#define g_MakeCenterDuplicateMgr() (CenterDuplicateMgr::Instance())
#define g_GetCenterDuplicateMgr()  (CenterDuplicateMgr::GetInstance())
#define g_DelCenterDuplicateMgr()  (CenterDuplicateMgr::Destroy())
